package repository;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;

public class Repository {
    private static class Singleton{
        private static Repository instance;
    }

    /**
     * 寻找根路径目录
     */
    public static void lookupRoot(){
        var cur = Path.of(".").toAbsolutePath();
        do{
            File jit = cur.resolve("./.jit").toFile();
            if(jit.exists() && jit.isDirectory()){
                Singleton.instance = new Repository(cur);
                return;
            }
            cur = cur.getParent();
        } while (cur != null);
        System.err.println("Fatal: No Jit Repository Found!");
        System.exit(-1);
    }

    public static Repository getInstance(){
        return Singleton.instance;
    }

    private final Path work_tree; // 工作目录
    private final Path repo_root; // 储存库路径

    private Repository(Path root){
        this.work_tree = root.toAbsolutePath();
        this.repo_root = this.work_tree.resolve(".jit");
    }

    public Path getWorkTree(){return work_tree;}
    public Path getRepoRoot(){return repo_root;}
    public Path getIndexPath(){return repo_root.resolve("index");}
    public Path getConfigPath(){return repo_root.resolve("config");}
    public Path getObjectPath(){return repo_root.resolve("objects");}
    public Path getRefHeadsPath(){return repo_root.resolve("refs").resolve("heads");}
    public Path getHeadPath(){return repo_root.resolve("HEAD");}

    /**
     * 判断文件路径是否存在
     * @return  返回true或false
     */
    public boolean exist(){
        File repo = repo_root.toFile();
        return repo.exists() && repo.isDirectory() && isValid();
    }
    public boolean isValid(){
        return true;
    }
    /**
     * 文件中获取index
     * @return
     * @throws IOException
     */
    public Index getIndex() throws IOException{
        Index index = Index.fromFile(getIndexPath().toFile());
        return index==null?new Index(): index;
    }
    /**
     * 获取配置文件内容
     * @return
     * @throws IOException
     */
    public Config getConfig() throws IOException{
        Config config = Config.fromFile(getConfigPath().toFile());
        return config == null? new Config(): config;
    }

    /**
     * 获取当前分支
     * @return 返回值为branch对象
     */
    public Branch getCurrentBranch(){
        var head = getHeadPath().toFile();
        if(!head.exists() || !head.isFile()){
            System.err.println("Fatal: Invalid HEAD file.");
            System.exit(-1);
        }
        try(var in = new BufferedReader(new FileReader(head, StandardCharsets.UTF_8))) {
            String line = in.readLine();
            String[] data = line.split(":\\s*", 2);
            if(!"ref".equals(data[0])){
                System.err.println("Fatal: Invalid HEAD file.");
                System.exit(-1);
            }
            return Branch.load(getRepoRoot().resolve(data[1]).toFile());
        } catch (FileNotFoundException e) {
            System.err.println("Fatal: Missing HEAD file.");
            System.exit(-1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    /**
     * 设置当前分支对象
     * @param branch  参数为branch对象
     */
    public void setCurrentBranch(Branch branch) {
        try(var out = new BufferedWriter(new FileWriter(getHeadPath().toFile()))){
            out.write(String.format("ref: refs/heads/%s", branch.getName()));
            out.flush();
        } catch (FileNotFoundException e){
            System.err.println("Fatal: Missing HEAD file.");
            System.exit(-1);
        } catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建一个仓库
     * <i>创建.jit文件夹以及其他仓库所需的文件和目录</i>
     */
    public static boolean createRepo(){
        Path root = Path.of("").toAbsolutePath();
        Path repo_root = root.resolve(".jit");
        if(repo_root.toFile().exists()){
            System.err.printf("Fatal: Repository Directory [%s] Already Exists!", repo_root.toString());
            return false;
        }
        if(!repo_root.toFile().mkdirs()){
            System.err.printf("Fatal: Failed to create directory: %s%n", repo_root);
            return false;
        }
        var repo = new Repository(root);
        for(Path path: Arrays.asList(
                repo.getObjectPath(),
                repo.getRefHeadsPath())
        ){
            if(!path.toFile().mkdirs()){
                System.err.printf("Failed create repo folder: %s%n",path);
                return false;
            }
        }
        repo.setCurrentBranch(new Branch(Branch.defaultMainBranch(), null));
        return true;
    }
}
